﻿#region Copyright (C) Sector7 Software Studio. All rights reserved
/*******************************************************************************************
 * Creation
 *      Author:         Wolf Lai
 *      Date:           2013/11/4 星期一 23:15:59
 *      Version:        
 * Modification 
 *      Author: 
 *      Date: 
 *      Description: 
 *      Version:
 *******************************************************************************************/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Sector7.Framework.Drivers.RF
{
    /// <summary>
    /// IC卡读卡器（MW_EYE_U010）
    /// </summary>
    public class RfReader_MW_EYE_U010 : RfReaderBase
    {
        #region External functions
        [DllImport("mwrf32.dll", EntryPoint = "rf_init", SetLastError = true,
               CharSet = CharSet.Auto, ExactSpelling = false,
               CallingConvention = CallingConvention.StdCall)]
        private static extern int rf_init(Int16 port, int baud);

        [DllImport("mwrf32.dll", EntryPoint = "rf_exit", SetLastError = true,
               CharSet = CharSet.Auto, ExactSpelling = false,
               CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_exit(int icdev);

        [DllImport("mwrf32.dll", EntryPoint = "rf_beep", SetLastError = true,
               CharSet = CharSet.Auto, ExactSpelling = false,
               CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_beep(int icdev, int msec);

        [DllImport("mwrf32.dll", EntryPoint = "rf_get_status", SetLastError = true,
              CharSet = CharSet.Auto, ExactSpelling = false,
              CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_get_status(int icdev, [MarshalAs(UnmanagedType.LPArray)]byte[] state);

        [DllImport("mwrf32.dll", EntryPoint = "rf_load_key", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_load_key(int icdev, int mode, int secnr, [MarshalAs(UnmanagedType.LPArray)]byte[] keybuff);

        [DllImport("mwrf32.dll", EntryPoint = "rf_load_key_hex", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_load_key_hex(int icdev, int mode, int secnr, [MarshalAs(UnmanagedType.LPArray)]byte[] keybuff);


        [DllImport("mwrf32.dll", EntryPoint = "a_hex", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 a_hex([MarshalAs(UnmanagedType.LPArray)]byte[] asc, [MarshalAs(UnmanagedType.LPArray)]byte[] hex, int len);

        [DllImport("mwrf32.dll", EntryPoint = "hex_a", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 hex_a([MarshalAs(UnmanagedType.LPArray)]byte[] hex, [MarshalAs(UnmanagedType.LPArray)]byte[] asc, int len);

        [DllImport("mwrf32.dll", EntryPoint = "rf_reset", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_reset(int icdev, int msec);

        [DllImport("mwrf32.dll", EntryPoint = "rf_request", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_request(int icdev, int mode, out UInt16 tagtype);


        [DllImport("mwrf32.dll", EntryPoint = "rf_anticoll", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_anticoll(int icdev, int bcnt, out uint snr);

        [DllImport("mwrf32.dll", EntryPoint = "rf_select", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_select(int icdev, uint snr, out byte size);

        [DllImport("mwrf32.dll", EntryPoint = "rf_card", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_card(int icdev, int mode, [MarshalAs(UnmanagedType.LPArray)]byte[] snr);

        [DllImport("mwrf32.dll", EntryPoint = "rf_authentication", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_authentication(int icdev, int mode, int secnr);

        [DllImport("mwrf32.dll", EntryPoint = "rf_authentication_2", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_authentication_2(int icdev, int mode, int keynr, int blocknr);

        [DllImport("mwrf32.dll", EntryPoint = "rf_read", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_read(int icdev, int blocknr, [MarshalAs(UnmanagedType.LPArray)]byte[] databuff);

        [DllImport("mwrf32.dll", EntryPoint = "rf_read_hex", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_read_hex(int icdev, int blocknr, [MarshalAs(UnmanagedType.LPArray)]byte[] databuff);

        [DllImport("mwrf32.dll", EntryPoint = "rf_write_hex", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_write_hex(int icdev, int blocknr, [MarshalAs(UnmanagedType.LPArray)]byte[] databuff);

        [DllImport("mwrf32.dll", EntryPoint = "rf_write", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_write(int icdev, int blocknr, [MarshalAs(UnmanagedType.LPArray)]byte[] databuff);

        [DllImport("mwrf32.dll", EntryPoint = "rf_halt", SetLastError = true,
             CharSet = CharSet.Auto, ExactSpelling = false,
             CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_halt(int icdev);

        [DllImport("mwrf32.dll", EntryPoint = "rf_changeb3", SetLastError = true,
            CharSet = CharSet.Auto, ExactSpelling = false,
            CallingConvention = CallingConvention.StdCall)]
        public static extern Int16 rf_changeb3(int icdev, int sector, [MarshalAs(UnmanagedType.LPArray)]byte[] keya, int B0, int B1,
              int B2, int B3, int Bk, [MarshalAs(UnmanagedType.LPArray)]byte[] keyb);
        #endregion

        #region Public functions

        public override int Initialize(short port, int baud)
        {
            m_port = port;
            m_baud = baud;

            m_handle = rf_init(m_port, m_baud);

            GenerateFaultId();

            return m_handle;
        }

        public override int LoadPassword(int keyMode, int sectorNumber, string password)
        {
            byte[] key = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

            if (m_handle > 0)
            {
                m_keyMode = keyMode;
                m_sectorNumber = sectorNumber;

                m_result = rf_load_key(m_handle, keyMode, sectorNumber, key);
            }

            return GenerateFaultId();
        }

        public override int SearchCard(int searchMode)
        {
            if (m_handle > 0)
            {
                byte[] __serialNumber = new byte[5];
                m_result = rf_card(m_handle, searchMode, __serialNumber);

                if (m_result == 0)
                {
                    byte[] serialNumber = new byte[8];
                    hex_a(__serialNumber, serialNumber, 4);
                    m_serialNumber = Encoding.UTF8.GetString(serialNumber);

                    m_result = rf_authentication(m_handle, m_keyMode, m_sectorNumber);
                }
            }

            return GenerateFaultId();
        }

        public override int ReadData(int address, byte[] data)
        {
            if (m_handle > 0)
            {
                m_result = rf_read(m_handle, address, data);
            }

            return GenerateFaultId();
        }

        public override int WriteData(int address, byte[] data)
        {
            if (m_handle > 0)
            {
                m_result = rf_write(m_handle, address, data);
            }

            return GenerateFaultId();
        }

        public override int ReleaseCard()
        {
            if (m_handle > 0)
            {
                m_result = rf_halt(m_handle);
            }

            return GenerateFaultId();
        }

        public override void Dispose()
        {
            if (m_handle > 0)
            {
                rf_exit(m_handle);
            }
        }

        public override int Beep(int duration)
        {
            return rf_beep(m_handle, duration);
        }
        #endregion

        #region Private functions

        protected override int GenerateFaultId()
        {
            if (m_handle > 0)
            {
                if (m_result == 0 || m_result == RfReader_ErrorCode.ERR_RF_SUCCESS)
                {
                    m_result = RfReader_ErrorCode.ERR_RF_SUCCESS;
                }
                else
                {
                    m_result += FAULT_ID_OFFSET;
                    throw new RfReaderException(m_result);
                }
            }
            else
            {
                m_result = RfReader_ErrorCode.ERR_RF_INIT_FAIL;
                throw new RfReaderException(m_result);
            }

            return m_result;
        }

        #endregion

        #region Structure
        #endregion

        #region Inner memeber
        /// <summary>
        /// MW_EYE_U010错误码偏移量
        /// </summary>
        private const int FAULT_ID_OFFSET = RfReader_ErrorCode.ERR_RF_MW101;

        /*
         * 搜索卡片模式
         * 选用ONCE模式寻卡时，完成对卡片的操作后调用rf_halt函数来停止操作，此后读写器不能找到卡片，除非卡片离开操作区域并再次重新进入。
         * 选用REPEAT模式寻卡时，完成对卡片的操作后调用rf_halt函数来停止操作，此后读写器仍能找到该卡片，无须离开操作区域并再次重新进入。
         */
        public const int SCAN_MODE_ONCE = 0;
        public const int SCAN_MODE_REPEAT = 1;
        public const int SCAN_MODE_ASSIGN = 2;

        /*
         * 密码验证模式
         * 对于M1卡的每个扇区，在读写器中只有一套密码(密码A和密码B)，动态库为了和RF-25兼容，
         * 仍对应三套密码（KEYSET0、KEYSET1、KEYSET2），每套密码包括A密码（KEYA）和B密码（KEYB），共六个密码，
         * 用0～2、4～6来表示这六个密码
         */
        public const int KEY_MODE_A0 = 0;
        public const int KEY_MODE_A1 = 1;
        public const int KEY_MODE_A2 = 2;
        public const int KEY_MODE_B0 = 4;
        public const int KEY_MODE_B1 = 5;
        public const int KEY_MODE_B2 = 6;
        #endregion
    }
}
